home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue58 / alfresco / AADES.pas next >
Encoding:
Pascal/Delphi Source File  |  2000-05-01  |  18.5 KB  |  536 lines

  1. {*********************************************************}
  2. {* AADES                                                 *}
  3. {* Copyright (c) Julian M Bucknall 2000                  *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco: DES encryption/decryption        *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AADES;
  14.  
  15. interface
  16.  
  17. uses
  18.   SysUtils,
  19.   Classes;
  20.  
  21. type
  22.   TaaDesKey64 = array [0..7] of byte;
  23.     {type for a DES key}
  24.   TaaDesBlock = array [0..7] of byte;
  25.     {type for a DES data block}
  26.  
  27.   TaaDesMode = ( {Different DES modes...}
  28.     dmECB,       {..ECB (Electronic Code Book)}
  29.     dmCBC);      {..CBC (Cipher Block Chaining)}
  30.  
  31. type
  32.   TaaDesEngine = class
  33.     private
  34.       FState      : pointer;
  35.       FKey        : TaaDesKey64;
  36.       FEncrypting : boolean;
  37.     protected
  38.     public
  39.       constructor Create(const aKey       : TaaDesKey64;
  40.                                aToEncrypt : boolean);
  41.       destructor Destroy; override;
  42.  
  43.       procedure ProcessBlock(const aSrc : TaaDesBlock;
  44.                                var aDest: TaaDesBlock);
  45.       procedure ProcessStream(aInStream  : TStream;
  46.                               aOutStream : TStream;
  47.                               aMode      : TaaDesMode);
  48.  
  49.       property Encrypting : boolean read FEncrypting;
  50.   end;
  51.  
  52.  
  53. implementation
  54.  
  55. type
  56.   T32bits      = array [0..3] of byte;
  57.   T48bits      = array [0..5] of byte;
  58.   TDesKeyArray = array [0..55] of boolean;
  59.   TSubKey      = T48bits;
  60.   PSubKeyArray = ^TSubKeyArray;
  61.   TSubKeyArray = array [1..16] of TSubKey;
  62.  
  63. const
  64.   BitMask : array [0..7] of byte =
  65.           ($80, $40, $20, $10, $08, $04, $02, $01);
  66.  
  67. const
  68.   DesKeyBitSelection : array [0..55] of byte =
  69.      (56, 48, 40, 32, 24, 16,  8,  0,
  70.       57, 49, 41, 33, 25, 17,  9,  1,
  71.       58, 50, 42, 34, 26, 18, 10,  2,
  72.       59, 51, 43, 35, 62, 54, 46, 38,
  73.       30, 22, 14,  6, 61, 53, 45, 37,
  74.       29, 21, 13,  5, 60, 52, 44, 36,
  75.       28, 20, 12,  4, 27, 19, 11,  3);
  76.  
  77.   DesSubKeyShifts : array [1..16] of byte =
  78.      (1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1);
  79.  
  80.   DesSubKeyPerm : array [0..47] of byte =
  81.     (13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9, 22, 18, 11,  3,
  82.      25,  7, 15,  6, 26, 19, 12,  1, 40, 51, 30, 36, 46, 54, 29, 39,
  83.      50, 44, 32, 47, 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31);
  84.  
  85.   DesStartPerm : array [0..63] of byte =
  86.      (57, 49, 41, 33, 25, 17,  9,  1, 59, 51, 43, 35, 27, 19, 11,  3,
  87.       61, 53, 45, 37, 29, 21, 13,  5, 63, 55, 47, 39, 31, 23, 15,  7,
  88.       56, 48, 40, 32, 24, 16,  8,  0, 58, 50, 42, 34, 26, 18, 10,  2,
  89.       60, 52, 44, 36, 28, 20, 12,  4, 62, 54, 46, 38, 30, 22, 14,  6);
  90.  
  91.   DesFinalPerm : array [0..63] of byte =
  92.      (39,  7, 47, 15, 55, 23, 63, 31, 38,  6, 46, 14, 54, 22, 62, 30,
  93.       37,  5, 45, 13, 53, 21, 61, 29, 36,  4, 44, 12, 52, 20, 60, 28,
  94.       35,  3, 43, 11, 51, 19, 59, 27, 34,  2, 42, 10, 50, 18, 58, 26,
  95.       33,  1, 41,  9, 49, 17, 57, 25, 32,  0, 40,  8, 48, 16, 56, 24);
  96.  
  97.   DesEBoxPerm : array [0..47] of byte =
  98.      (31,  0,  1,  2,  3,  4,  3,  4,  5,  6,  7,  8,
  99.        7,  8,  9, 10, 11, 12, 11, 12, 13, 14, 15, 16,
  100.       15, 16, 17, 18, 19, 20, 19, 20, 21, 22, 23, 24,
  101.       23, 24, 25, 26, 27, 28, 27, 28, 29, 30, 31,  0);
  102.  
  103.   DesSBox1 : array [0..63] of byte =
  104.      (14,  0,  4, 15, 13,  7,  1,  4,  2, 14, 15,  2, 11, 13,  8,  1,
  105.        3, 10, 10,  6,  6, 12, 12, 11,  5,  9,  9,  5,  0,  3,  7,  8,
  106.        4, 15,  1, 12, 14,  8,  8,  2, 13,  4,  6,  9,  2,  1, 11,  7,
  107.       15,  5, 12, 11,  9,  3,  7, 14,  3, 10, 10,  0,  5,  6,  0, 13);
  108.  
  109.   DesSBox2 : array [0..63] of byte =
  110.      (15,  3,  1, 13,  8,  4, 14,  7,  6, 15, 11,  2,  3,  8,  4, 14,
  111.        9, 12,  7,  0,  2,  1, 13, 10, 12,  6,  0,  9,  5, 11, 10,  5,
  112.        0, 13, 14,  8,  7, 10, 11,  1, 10,  3,  4, 15, 13,  4,  1,  2,
  113.        5, 11,  8,  6, 12,  7,  6, 12,  9,  0,  3,  5,  2, 14, 15,  9);
  114.  
  115.   DesSBox3 : array [0..63] of byte =
  116.      (10, 13,  0,  7,  9,  0, 14,  9,  6,  3,  3,  4, 15,  6,  5, 10,
  117.        1,  2, 13,  8, 12,  5,  7, 14, 11, 12,  4, 11,  2, 15,  8,  1,
  118.       13,  1,  6, 10,  4, 13,  9,  0,  8,  6, 15,  9,  3,  8,  0,  7,
  119.       11,  4,  1, 15,  2, 14, 12,  3,  5, 11, 10,  5, 14,  2,  7, 12);
  120.  
  121.   DesSBox4 : array [0..63] of byte =
  122.      ( 7, 13, 13,  8, 14, 11,  3,  5,  0,  6,  6, 15,  9,  0, 10,  3,
  123.        1,  4,  2,  7,  8,  2,  5, 12, 11,  1, 12, 10,  4, 14, 15,  9,
  124.       10,  3,  6, 15,  9,  0,  0,  6, 12, 10, 11,  1,  7, 13, 13,  8,
  125.       15,  9,  1,  4,  3,  5, 14, 11,  5, 12,  2,  7,  8,  2,  4, 14);
  126.  
  127.   DesSBox5 : array [0..63] of byte =
  128.      ( 2, 14, 12, 11,  4,  2,  1, 12,  7,  4, 10,  7, 11, 13,  6,  1,
  129.        8,  5,  5,  0,  3, 15, 15, 10, 13,  3,  0,  9, 14,  8,  9,  6,
  130.        4, 11,  2,  8,  1, 12, 11,  7, 10,  1, 13, 14,  7,  2,  8, 13,
  131.       15,  6,  9, 15, 12,  0,  5,  9,  6, 10,  3,  4,  0,  5, 14,  3);
  132.  
  133.   DesSBox6 : array [0..63] of byte =
  134.      (12, 10,  1, 15, 10,  4, 15,  2,  9,  7,  2, 12,  6,  9,  8,  5,
  135.        0,  6, 13,  1,  3, 13,  4, 14, 14,  0,  7, 11,  5,  3, 11,  8,
  136.        9,  4, 14,  3, 15,  2,  5, 12,  2,  9,  8,  5, 12, 15,  3, 10,
  137.        7, 11,  0, 14,  4,  1, 10,  7,  1,  6, 13,  0, 11,  8,  6, 13);
  138.  
  139.   DesSBox7 : array [0..63] of byte =
  140.      ( 4, 13, 11,  0,  2, 11, 14,  7, 15,  4,  0,  9,  8,  1, 13, 10,
  141.        3, 14, 12,  3,  9,  5,  7, 12,  5,  2, 10, 15,  6,  8,  1,  6,
  142.        1,  6,  4, 11, 11, 13, 13,  8, 12,  1,  3,  4,  7, 10, 14,  7,
  143.       10,  9, 15,  5,  6,  0,  8, 15,  0, 14,  5,  2,  9,  3,  2, 12);
  144.  
  145.   DesSBox8 : array [0..63] of byte =
  146.      (13,  1,  2, 15,  8, 13,  4,  8,  6, 10, 15,  3, 11,  7,  1,  4,
  147.       10, 12,  9,  5,  3,  6, 14, 11,  5,  0,  0, 14, 12,  9,  7,  2,
  148.        7,  2, 11,  1,  4, 14,  1,  7,  9,  4, 12, 10, 14,  8,  2, 13,
  149.        0, 15,  6, 12, 10,  9, 13,  0, 15,  3,  3,  5,  5,  6,  8, 11);
  150.  
  151.   DesPBoxPerm : array [0..31] of byte =
  152.      (15,  6, 19, 20, 28, 11, 27, 16,  0, 14, 22, 25,  4, 17, 30,  9,
  153.        1,  7, 23, 13, 31, 26,  2,  8, 18, 12, 29,  5, 21, 10,  3, 24);
  154.  
  155.  
  156. {===Helper routines==================================================}
  157. procedure CalcPermutation(const aSource;
  158.                             var aDest;
  159.                           const aMapping;
  160.                                 aMapCount : integer);
  161. var
  162.   Src  : TByteArray absolute aSource;
  163.   Dest : TByteArray absolute aDest;
  164.   Map  : TByteArray absolute aMapping;
  165.   i    : integer;
  166.   FromByte : integer;
  167.   FromBit  : integer;
  168.   ToByte   : integer;
  169.   Accum    : byte;
  170.   CurBit   : byte;
  171. begin
  172.   {using the mapping, transfer bits from source to destination}
  173.   ToByte := 0;
  174.   Accum := 0;
  175.   CurBit := $80;
  176.   for i := 0 to pred(aMapCount) do begin
  177.     FromByte := Map[i] div 8;
  178.     FromBit := Map[i] mod 8;
  179.     if ((Src[FromByte] and BitMask[FromBit]) <> 0) then
  180.       Accum := Accum or CurBit;
  181.     CurBit := CurBit shr 1;
  182.     if (CurBit = 0) then begin
  183.       Dest[ToByte] := Accum;
  184.       inc(ToByte);
  185.       Accum := 0;
  186.       CurBit := $80;
  187.     end;
  188.   end;
  189. end;
  190. {--------}
  191. procedure CalcSubKeys(const aKey56      : TDesKeyArray;
  192.                         var aSubKeys    : TSubKeyArray;
  193.                             aForEncrypt : boolean);
  194. var
  195.   i        : integer;
  196.   LeftInx  : integer;
  197.   ToInx    : integer;
  198.   Round    : integer;
  199.   Temp56   : TDesKeyArray;
  200.   SubKey   : TSubKey;
  201.   ToByte   : integer;
  202.   Accum    : byte;
  203.   CurBit   : byte;
  204.   TotalRotation : integer;
  205. begin
  206.   {calculate the subkeys for all 16 rounds...}
  207.   for Round := 1 to 16 do begin
  208.     {calculate the total rotation required for this round}
  209.     TotalRotation := 0;
  210.     for i := 1 to Round do
  211.       inc(TotalRotation, DesSubKeyShifts[i]);
  212.     {left rotate the two halves of the 56-bit key by the
  213.      required shift for this round}
  214.     for LeftInx := 0 to 27 do begin
  215.       {calculate the next destination index}
  216.       ToInx := LeftInx - TotalRotation;
  217.       if (ToInx < 0) then {we have wrapped}
  218.         inc(ToInx, 28);
  219.       {move the bit from the original key to our temp key,
  220.        first for the left half and then for the right half}
  221.       Temp56[ToInx] := aKey56[LeftInx];
  222.       Temp56[ToInx+28] := aKey56[LeftInx+28];
  223.     end;
  224.     {now calculate this round's subkey by selecting the correct bits}
  225.     ToByte := 0;
  226.     Accum := 0;
  227.     CurBit := $80;
  228.     for i := 0 to 47 do begin
  229.       if Temp56[DesSubKeyPerm[i]] then
  230.         Accum := Accum or CurBit;
  231.       CurBit := CurBit shr 1;
  232.       if (CurBit = 0) then begin
  233.         SubKey[ToByte] := Accum;
  234.         inc(ToByte);
  235.         Accum := 0;
  236.         CurBit := $80;
  237.       end;
  238.     end;
  239.     {save the subkey
  240.      note: for decryption we save subkeys in reverse order}
  241.     if aForEncrypt then
  242.       aSubKeys[Round] := SubKey
  243.     else
  244.       aSubKeys[17-Round] := SubKey;
  245.   end;
  246. end;
  247. {--------}
  248. procedure ConvertDesKey(const aDesKey64 : TaaDesKey64;
  249.                           var aKey56    : TDesKeyArray);
  250. var
  251.   i : integer;
  252.   ByteNum : integer;
  253.   BitNum  : integer;
  254. begin
  255.   {for each outbit bit...}
  256.   for i := 0 to 55 do begin
  257.     {work out which byte in the input key and which bit within
  258.      that byte that the output bit will be found}
  259.     ByteNum := DesKeyBitSelection[i] div 8;
  260.     BitNum := DesKeyBitSelection[i] mod 8;
  261.     {set the output boolean equal to this bit}
  262.     aKey56[i] := (aDesKey64[ByteNum] and BitMask[BitNum]) <> 0;
  263.   end;
  264. end;
  265. {--------}
  266. function F(const aRight : longint; const aSubKey : TSubKey) : longint;
  267. var
  268.   i        : integer;
  269.   BigRight : T48Bits;
  270.   Accum    : byte;
  271.   Temp32   : T32Bits;
  272. begin
  273.   {start off with the expansion permutation: the E-Box}
  274.   CalcPermutation(aRight, BigRight, DesEBoxPerm, sizeof(DesEBoxPerm));
  275.  
  276.   {XOR the subkey into the expanded data}
  277.   for i := 0 to 5 do
  278.     BigRight[i] := BigRight[i] xor aSubKey[i];
  279.  
  280.   {now wade into the S-Boxes}
  281.   {..first}
  282.   Accum := (BigRight[0] and $FC) shr 2;
  283.   Temp32[0] := DesSBox1[Accum] shl 4;
  284.   {..second}
  285.   Accum := ((BigRight[0] and $03) shl 4) or
  286.            ((BigRight[1] and $F0) shr 4);
  287.   Temp32[0] := Temp32[0] or DesSBox2[Accum];
  288.   {..third}
  289.   Accum := ((BigRight[1] and $0F) shl 2) or
  290.            ((BigRight[2] and $C0) shr 6);
  291.   Temp32[1] := DesSBox3[Accum] shl 4;
  292.   {..fourth}
  293.   Accum := (BigRight[2] and $3F);
  294.   Temp32[1] := Temp32[1] or DesSBox4[Accum];
  295.   {..fifth}
  296.   Accum := (BigRight[3] and $FC) shr 2;
  297.   Temp32[2] := DesSBox5[Accum] shl 4;
  298.   {..sixth}
  299.   Accum := ((BigRight[3] and $03) shl 4) or
  300.            ((BigRight[4] and $F0) shr 4);
  301.   Temp32[2] := Temp32[2] or DesSBox6[Accum];
  302.   {..seventh}
  303.   Accum := ((BigRight[4] and $0F) shl 2) or
  304.            ((BigRight[5] and $C0) shr 6);
  305.   Temp32[3] := DesSBox7[Accum] shl 4;
  306.   {..eighth}
  307.   Accum := (BigRight[5] and $3F);
  308.   Temp32[3] := Temp32[3] or DesSBox8[Accum];
  309.  
  310.   {end up with the final permutation: the P-Box}
  311.   CalcPermutation(Temp32, Result, DesPBoxPerm, sizeof(DesPBoxPerm));
  312. end;
  313. {--------}
  314. procedure XorDesBlock(const aSource : TaaDesBlock;
  315.                         var aDest   : TaaDesBlock);
  316. var
  317.   i : integer;
  318. begin
  319.   for i := 0 to pred(sizeof(TaaDesBlock)) do
  320.     aDest[i] := aDest[i] xor aSource[i];
  321. end;
  322. {====================================================================}
  323.  
  324.  
  325. {===TaaDesEngine=====================================================}
  326. constructor TaaDesEngine.Create(const aKey       : TaaDesKey64;
  327.                                       aToEncrypt : boolean);
  328. var
  329.   Temp56 : TDesKeyArray;
  330. begin
  331.   inherited Create;
  332.   {save parameters}
  333.   FKey := aKey;
  334.   FEncrypting := aToEncrypt;
  335.   {allocate the subkey array}
  336.   FState := AllocMem(sizeof(TSubKeyArray));
  337.   {convert the DES key and create the subkeys}
  338.   ConvertDesKey(FKey, Temp56);
  339.   CalcSubKeys(Temp56, PSubKeyArray(FState)^, Encrypting);
  340. end;
  341. {--------}
  342. destructor TaaDesEngine.Destroy;
  343. begin
  344.   {free the subkey array}
  345.   if (FState <> nil) then
  346.     FreeMem(FState, sizeof(TSubKeyArray));
  347.   inherited Destroy;
  348. end;
  349. {--------}
  350. procedure TaaDesEngine.ProcessBlock(const aSrc : TaaDesBlock;
  351.                                       var aDest: TaaDesBlock);
  352. var
  353.   Round : integer;
  354.   Temp  : longint;
  355.   Block : packed record
  356.     Left  : longint;
  357.     Right : longint;
  358.   end;
  359. begin
  360.   {perform the initial permutation of the source block}
  361.   CalcPermutation(aSrc, Block, DesStartPerm, sizeof(DesStartPerm));
  362.  
  363.   {do the 16 rounds}
  364.   for Round := 1 to 16 do begin
  365.     Temp := Block.Right;
  366.     Block.Right := Block.Left xor
  367.                    F(Block.Right, PSubKeyArray(FState)^[Round]);
  368.     Block.Left := Temp;
  369.   end;
  370.  
  371.   {this will have done one too many swaps of the right and
  372.    left halves, so swap them back}
  373.   Temp := Block.Right;
  374.   Block.Right := Block.Left;
  375.   Block.Left := Temp;
  376.  
  377.   {perform the final permutation of the source block}
  378.   CalcPermutation(Block, aDest, DesFinalPerm, sizeof(DesFinalPerm));
  379. end;
  380. {--------}
  381. procedure TaaDesEngine.ProcessStream(aInStream  : TStream;
  382.                                      aOutStream : TStream;
  383.                                      aMode      : TaaDesMode);
  384. var
  385.   i              : integer;
  386.   InSize         : longint;
  387.   BlockCount     : integer;
  388.   TotalBlockCount: integer;
  389.   FullBlockCount : integer;
  390.   BlocksToGo     : integer;
  391.   BytesRead      : longint;
  392.   LastBlock      : TaaDesBlock;
  393.   ThisBlock      : TaaDesBlock;
  394.   LastChunkIn    : array [0..1] of TaaDesBlock;
  395.   LastChunkOut   : array [0..1] of TaaDesBlock;
  396.   Buffer         : array [0..127] of TaaDesBlock;
  397. begin
  398.   {reposition the two streams}
  399.   aInStream.Position := 0;
  400.   aOutStream.Position := 0;
  401.  
  402.   {calculate the total number of blocks we shall be encoding, and
  403.    the number of complete blocks}
  404.   InSize := aInStream.Size;
  405.   TotalBlockCount := (InSize + 7) div sizeof(TaaDesBlock);
  406.   FullBlockCount := InSize div sizeof(TaaDesBlock);
  407.  
  408.   {prepare for CBC mode by setting the last block to binary zero}
  409.   if (aMode = dmCBC) then
  410.     FillChar(LastBlock, sizeof(LastBlock), 0);
  411.  
  412.   {if the total number of blocks equals the number of complete blocks,
  413.    then all we need to do is to process them all: there is no partial
  414.    block at the end to complicate things}
  415.   if (FullBlockCount = TotalBlockCount) then begin
  416.     BytesRead := aInStream.Read(Buffer, sizeof(Buffer));
  417.     while (BytesRead <> 0) do begin
  418.       BlockCount := BytesRead div sizeof(TaaDesBlock);
  419.       {either: en/decryption with ECB mode...}
  420.       if (aMode = dmECB) then begin
  421.         for i := 0 to pred(BlockCount) do
  422.           ProcessBlock(Buffer[i], Buffer[i]);
  423.       end
  424.       {or: encryption with CBC mode...}
  425.       else if Encrypting then begin
  426.         for i := 0 to pred(BlockCount) do begin
  427.           XorDesBlock(LastBlock, Buffer[i]);
  428.           ProcessBlock(Buffer[i], LastBlock);
  429.           Buffer[i] := LastBlock;
  430.         end
  431.       end
  432.       {otherwise: decryption with CBC mode...}
  433.       else begin
  434.         for i := 0 to pred(BlockCount) do begin
  435.           ProcessBlock(Buffer[i], ThisBlock);
  436.           XorDesBlock(LastBlock, ThisBlock);
  437.           LastBlock := Buffer[i];
  438.           Buffer[i] := ThisBlock;
  439.         end
  440.       end;
  441.       aOutStream.WriteBuffer(Buffer, BytesRead);
  442.       BytesRead := aInStream.Read(Buffer, sizeof(Buffer));
  443.     end;
  444.   end
  445.  
  446.   {otherwise we have a partial block at the end of the input stream}
  447.   else begin
  448.     {first process everything except the last full block and the
  449.      final partial block}
  450.     BlocksToGo := FullBlockCount - 1;
  451.     while (BlocksToGo <> 0) do begin
  452.       BlockCount := BlocksToGo;
  453.       if (BlockCount > 128) then
  454.         BlockCount := 128;
  455.       aInStream.ReadBuffer(Buffer, BlockCount * sizeof(TaaDesBlock));
  456.       {either: en/decryption with ECB mode...}
  457.       if (aMode = dmECB) then begin
  458.         for i := 0 to pred(BlockCount) do
  459.           ProcessBlock(Buffer[i], Buffer[i]);
  460.       end
  461.       {or: encryption with CBC mode...}
  462.       else if Encrypting then begin
  463.         for i := 0 to pred(BlockCount) do begin
  464.           XorDesBlock(LastBlock, Buffer[i]);
  465.           ProcessBlock(Buffer[i], LastBlock);
  466.           Buffer[i] := LastBlock;
  467.         end
  468.       end
  469.       {otherwise: decryption with CBC mode...}
  470.       else begin
  471.         for i := 0 to pred(BlockCount) do begin
  472.           ProcessBlock(Buffer[i], ThisBlock);
  473.           XorDesBlock(LastBlock, ThisBlock);
  474.           LastBlock := Buffer[i];
  475.           Buffer[i] := ThisBlock;
  476.         end
  477.       end;
  478.       aOutStream.WriteBuffer(Buffer, BlockCount * sizeof(TaaDesBlock));
  479.       dec(BlocksToGo, BlockCount);
  480.     end;
  481.  
  482.     {now read the final full and partial blocks
  483.      (note that BytesRead will equal 9, 10, .., 15)}
  484.     BytesRead := aInStream.Read(LastChunkIn, sizeof(LastChunkIn));
  485.  
  486.     {either: en/decryption with ECB mode...}
  487.     if (aMode = dmECB) then begin
  488.       {process the last full block}
  489.       ProcessBlock(LastChunkIn[0], LastChunkOut[1]);
  490.       {borrow enough bytes from the processed block to
  491.        fill out the final partial block}
  492.       for i := (BytesRead - 8) to 7 do
  493.         LastChunkIn[1][i] := LastChunkOut[1][i];
  494.       {process the filled block}
  495.       ProcessBlock(LastChunkIn[1], LastChunkOut[0])
  496.     end
  497.  
  498.     {or: encryption with CBC mode...}
  499.     else if Encrypting then begin
  500.       {process the last full block}
  501.       XorDesBlock(LastBlock, LastChunkIn[0]);
  502.       ProcessBlock(LastChunkIn[0], LastBlock);
  503.       LastChunkOut[1] := LastBlock;
  504.       {zero out the rest of the final partial block}
  505.       for i := (BytesRead - 8) to 7 do
  506.         LastChunkIn[1][i] := 0;
  507.       {process the filled block}
  508.       XorDesBlock(LastBlock, LastChunkIn[1]);
  509.       ProcessBlock(LastChunkIn[1], LastChunkOut[0]);
  510.     end
  511.  
  512.     {otherwise: decryption with CBC mode...}
  513.     else begin
  514.       {zero out the rest of the final partial block}
  515.       for i := (BytesRead - 8) to 7 do
  516.         LastChunkIn[1][i] := 0;
  517.       {process the last full block}
  518.       ProcessBlock(LastChunkIn[0], LastChunkOut[1]);
  519.       XorDesBlock(LastChunkIn[1], LastChunkOut[1]);
  520.       {borrow enough bytes from the processed block to
  521.        fill out the final partial block}
  522.       for i := (BytesRead - 8) to 7 do
  523.         LastChunkIn[1][i] := LastChunkOut[1][i];
  524.       {process the filled block}
  525.       ProcessBlock(LastChunkIn[1], LastChunkOut[0]);
  526.       XorDesBlock(LastBlock, LastChunkOut[0]);
  527.     end;
  528.  
  529.     {write the final full and partial blocks}
  530.     aOutStream.WriteBuffer(LastChunkOut, BytesRead);
  531.   end;
  532. end;
  533. {====================================================================}
  534.  
  535. end.
  536.